目前系統的頁面還是使用 ASP.NET Core MVC 的原始版面,看上去其實也不太美觀,剛好它本來就有使用 Bootstrap,那麼今天就使用 Bootstrap 的 Card 元件來讓活動列表更好看。
也會使用 View Component,藉由 View Component 來讓頁面顯示幻燈片的元件,其中幻燈片展示的是現在的活動以及該活動上傳的圖片。
將原本的 Code 刪除,並貼上以下 Code:
<div class="row">
<div class="col-lg-12">
<h4>精選活動</h4>
<hr />
<div class="row">
@foreach (var e in Model.EventsCollection)
{
<div class="col-lg-4">
<div class="card" style="width: 18rem;">
@if (e.EventsImage.Count() > 0)
{
<img src="~/images/Upload/Events/@e.EventsImage.FirstOrDefault().ImageFilePath" class="card-img-top" asp-append-version="true" />
}
else
{
<img src="~/images/logo.png" class="card-img-top" alt="...">
}
<div class="card-body">
<h5 class="card-title">@e.Title</h5>
<h6 class="card-subtitle mb-2 text-muted">@e.ProgressTimeStart.ToString("yyyy-MM-dd(dddd)") ~ <br>@e.ProgressTimeStart.ToString("yyyy-MM-dd(dddd)")</h6>
<p class="card-text">@e.SimpleIntro</p>
<a asp-controller="Events" asp-action="Details" asp-route-Id="@e.Id" class="btn btn-primary">查看更多</a>
</div>
</div>
</div>
}
</div>
</div>
</div>
迴圈判斷 EventsImage 數量是否大於 0,若有則顯示已上傳的圖片;
若無則顯示預設 Logo。
並且將活動名稱、簡稱、活動時間等放在 Card 的顯示欄位中。
View Component 與 Partial View 的差異在於,Partial View 主要是減少重複的 HTML,而 View Component 就像是一個小型 Controller 與 View 的結合。
View Component 可以在後端撰寫商業邏輯,或是寫入一些第三方的套件,並且在任何地方皆可呼叫,e.g. 購物車、Facebook Messenger API 等。
而這裡我會使用在 Bootstrap 的投影片元件上,後端則是呼叫最新的活動。
在專案新增 ViewComponents 的資料夾,並新增 ShowEventsCarousel 類別:
public async Task<IEnumerable<Events>> GetTheNewestEventsAsync(int count)
{
string SqlScript = $"EXECUTE dbo.GetTheNewestEvents @Count = {count}";
var events = await _appDbContext.Events.FromSqlRaw(SqlScript).ToListAsync();
foreach (var item in events)
{
item.EventsInfo = _appDbContext.EventsInfo.Where(
ei => ei.EventsInfoOfEventsId == item.Id
).FirstOrDefault();
item.EventsImage = _appDbContext.EventsImage.Where(
ei => ei.EventsId == item.Id
).ToList();
}
return events;
}
在 Views/Shared 新增 Components/ShowEventsCarousel 資料夾,再新增 Default.cshtml 檔案:
@model EventsListViewModel
<div class="row">
<div class="col-lg-12">
<div id="carouselExampleIndicators" class="carousel slide" data-ride="carousel">
<ol class="carousel-indicators">
@for (int i = 0; i < Model.EventsCollection.ToList().Count; i++)
{
if (i == 0)
{
<li data-target="#carouselExampleIndicators" data-slide-to="@i" class="active"></li>
}
else
{
<li data-target="#carouselExampleIndicators" data-slide-to="@i"></li>
}
}
</ol>
<div class="carousel-inner">
@for (int i = 0; i < Model.EventsCollection.ToList().Count; i++)
{
if (i == 0)
{
<div class="carousel-item active">
<a asp-controller="Events" asp-action="Details" asp-route-Id="@Model.EventsCollection.ToList()[i].Id">
@{
if (@Model.EventsCollection.ToList()[i].EventsImage.Count() > 0)
{
<img class="d-block w-100" src="~/images/Upload/Events/@Model.EventsCollection.ToList()[i].EventsImage.FirstOrDefault().ImageFileName" alt="@Model.EventsCollection.ToList()[i].Title">
}
else
{
<img class="d-block w-100" src="~/images/logo.png" alt="@Model.EventsCollection.ToList()[i].Title">
}
}
</a>
</div>
}
else
{
<div class="carousel-item">
<a asp-controller="Events" asp-action="Details" asp-route-Id="@Model.EventsCollection.ToList()[i].Id">
@{
if (@Model.EventsCollection.ToList()[i].EventsImage.Count() > 0)
{
<img class="d-block w-100" src="~/images/Upload/Events/@Model.EventsCollection.ToList()[i].EventsImage.FirstOrDefault().ImageFileName" alt="@Model.EventsCollection.ToList()[i].Title">
}
else
{
<img class="d-block w-100" src="~/images/logo.png" alt="@Model.EventsCollection.ToList()[i].Title">
}
}
</a>
</div>
}
}
</div>
</div>
<a class="carousel-control-prev" href="#carouselExampleIndicators" role="button" data-slide="prev">
<span class="carousel-control-prev-icon" aria-hidden="true"></span>
<span class="sr-only">Previous</span>
</a>
<a class="carousel-control-next" href="#carouselExampleIndicators" role="button" data-slide="next">
<span class="carousel-control-next-icon" aria-hidden="true"></span>
<span class="sr-only">Next</span>
</a>
</div>
</div>
<style>
.carousel-item {
height: 400px;
}
.carousel-item img {
height: 400px;
}
</style>
建立一個可以取得最新建立的活動,並可以指定傳回多少筆數的資料,而取資料的方式是再撰寫一個 Stored Procedure:
public async Task<IEnumerable<Events>> GetTheNewestEventsAsync(int count)
{
string SqlScript = $"EXECUTE dbo.GetTheNewestEvents @Count = {count}";
var events = await _appDbContext.Events.FromSqlRaw(SqlScript).ToListAsync();
return events;
}
USE EventsSystem
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [GetTheNewestEvents]
@Count INT = 5
AS
BEGIN
SET NOCOUNT ON;
DECLARE @SQLScript NVARCHAR(MAX)
SET @SQLScript =
'
SELECT TOP (' + CAST(@Count AS VARCHAR(5)) + ') T_E.[Id]
,T_E.[Title]
,T_EI.[Location]
,T_E.[SimpleIntro]
,T_E.[CategoryId]
,T_E.[ProgressTimeStart]
,T_E.[ProgressTimeEnd]
,T_E.[SaleTimeStart]
,T_E.[SaleTimeEnd]
,T_EI.[ApplicationLimitedQty]
,T_EI.[EventsApplicationQty]
,T_E.[CreateTime]
,T_E.[CreateUser]
,T_E.[UpdateTime]
,T_E.[UpdateUser]
FROM [dbo].[Events] AS T_E
LEFT JOIN [dbo].[EventsInfo] AS T_EI
ON T_E.[Id] = T_EI.[EventsInfoOfEventsId]
ORDER BY T_E.[CreateTime] DESC
'
EXEC (@SQLScript)
END
GO
加入參考 @using EventsSystem_iThome.ViewComponents
加入 @await Component.InvokeAsync(nameof(ShowEventsCarousel))
實際用上 View Component 或是 Partial View,都可以讓 HTML 本身的 Code 減少很多,而且重用性很高,比如說今天要抓出站台的總瀏覽人數,就可以寫在 View Component 並且在各種不同的頁面呼叫。
對了,鐵人賽斷在 28 天的原因下一篇會說~
下一篇會寫下這整個月的心路歷程,以及一些領悟到的事情。
那麼明天見~
[鐵人賽Day13] - View(3) / Partial View及View Component